package com.wsoft.hr.pm.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wsoft.bpm.bean.ApprovalChainNode;
import com.wsoft.bpm.bean.DynamicApprovalChain;
import com.wsoft.bpm.entity.ActProcessMappingEntity;
import com.wsoft.bpm.enums.ApproveStatus;
import com.wsoft.bpm.query.mapping.ExtraBusinessDataQuery;
import com.wsoft.bpm.service.IActProcessMappingService;
import com.wsoft.bpm.service.WorkFlowService;
import com.wsoft.constant.CommonConstant;
import com.wsoft.core.enums.DcOpenTypeEnum;
import com.wsoft.core.exception.ApiException;
import com.wsoft.core.exception.Asserts;
import com.wsoft.core.service.CommonMemberService;
import com.wsoft.core.utils.TableNameUtils;
import com.wsoft.core.validate.ValidList;
import com.wsoft.core.vo.MemberVO;
import com.wsoft.entity.BaseEntity;
import com.wsoft.hr.pm.constant.HrPmCodeConstant;
import com.wsoft.hr.pm.entity.*;
import com.wsoft.hr.pm.enums.HrProcessFlowStageEnum;
import com.wsoft.hr.pm.enums.ProcessCardAssignTypeEnum;
import com.wsoft.hr.pm.manager.*;
import com.wsoft.hr.pm.mapper.HrPmProcessActivityMapper;
import com.wsoft.hr.pm.query.process.activity.HrPmProcessActivityQuery;
import com.wsoft.hr.pm.query.process.activity.HrPmProcessActivitySaveQuery;
import com.wsoft.hr.pm.query.process.activity.HrProcessActivityCardQuery;
import com.wsoft.hr.pm.service.IHrPmProcessActivityService;
import com.wsoft.hr.pm.vo.process.activity.HrPmProcessActivityDataVO;
import com.wsoft.hr.pm.vo.process.activity.HrPmProcessActivityVO;
import com.wsoft.hr.pm.vo.process.activity.HrProcessActivityCardVO;
import com.wsoft.hr.pm.vo.process.activity.ProcessActivityNodeVO;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 活动考核流程主表 服务实现类
 * </p>
 *
 * @author zhonglj
 * @since 2025年02月28日 18:19:01
 */
@Service
public class HrPmProcessActivityServiceImpl extends ServiceImpl<HrPmProcessActivityMapper, HrPmProcessActivityEntity> implements IHrPmProcessActivityService {
    @Resource
    private HrPmProcessActivityManager processActivityManager;
    @Resource
    private HrPmProcessActivityCardManager processActivityCardManager;
    @Resource
    private HrPmProcessTemplateManager processTemplateManager;
    @Resource
    private HrPmProcessTemplateCardManager processTemplateCardManager;

    @Override
    public HrPmProcessActivityDataVO getByMemberTemplateId(Long memberTemplateId) {
        HrPmProcessActivityDataVO resultVO = new HrPmProcessActivityDataVO();
        List<HrPmProcessActivityEntity> activityEntities = processActivityManager.list(
                Wrappers.lambdaQuery(HrPmProcessActivityEntity.class)
                        .eq(HrPmProcessActivityEntity::getMemberTemplateId, memberTemplateId)
                        .orderByAsc(HrPmProcessActivityEntity::getSort)
        );

        if (CollUtil.isEmpty(activityEntities)) {
            return resultVO;
        }

        resultVO.setMemberTemplateId(memberTemplateId);
        List<HrPmProcessActivityVO> vos = CollUtil.newArrayList();
        for (HrPmProcessActivityEntity processActivityEntity : activityEntities) {
            // 设置每一个阶段的卡片
            HrPmProcessActivityVO processActivityVO = Convert.convert(HrPmProcessActivityVO.class, processActivityEntity);

            List<HrPmProcessActivityCardEntity> processActivityCard = processActivityCardManager.list(
                    Wrappers.lambdaQuery(HrPmProcessActivityCardEntity.class)
                            .eq(HrPmProcessActivityCardEntity::getPid, processActivityEntity.getId())
                            .orderByAsc(HrPmProcessActivityCardEntity::getSerialSort)
                            .orderByAsc(HrPmProcessActivityCardEntity::getParallelSort)
            );
            processActivityVO.setCards(processActivityCard.stream()
                    .map(e -> Convert.convert(HrProcessActivityCardVO.class, e))
                    .collect(Collectors.toList()));

            vos.add(processActivityVO);
        }

        resultVO.setFlowStages(vos);
        return resultVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE)
    public void saveProcess(HrPmProcessActivitySaveQuery saveQuery) {
        Long memberTemplateId = saveQuery.getMemberTemplateId();
        List<HrPmProcessActivityQuery> templates = saveQuery.getFlowStages();

        List<HrPmProcessActivityEntity> existActivity = processActivityManager.list(
                Wrappers.lambdaQuery(HrPmProcessActivityEntity.class)
                        .eq(HrPmProcessActivityEntity::getMemberTemplateId, memberTemplateId)
        );

        if (CollUtil.isNotEmpty(existActivity)) {
            List<Long> existActivityIds = existActivity.stream().map(BaseEntity::getId).collect(Collectors.toList());
            // 删除主表原始数据
            processActivityManager.removeByIds(existActivityIds);

            // 删除卡片表原始数据
            processActivityCardManager.remove(
                    Wrappers.lambdaQuery(HrPmProcessActivityCardEntity.class)
                            .in(HrPmProcessActivityCardEntity::getPid, existActivityIds)
            );
        }


        for (HrPmProcessActivityQuery templateQuery : templates) {
            // 保存主表
            HrPmProcessActivityEntity processActivityEntity = Convert.convert(HrPmProcessActivityEntity.class, templateQuery);
            processActivityEntity.setMemberTemplateId(memberTemplateId);
            processActivityManager.save(processActivityEntity);
            Long pid = processActivityEntity.getId();

            // 保存卡片表
            ValidList<HrProcessActivityCardQuery> cards = templateQuery.getCards();
            if (CollUtil.isNotEmpty(cards)) {
                List<HrPmProcessActivityCardEntity> cardEntities = new ArrayList<>();
                String serialUuid = Opt.ofBlankAble(cards.get(0).getSerialUuid()).orElse(IdUtil.fastSimpleUUID());
                for (int i = 0; i < cards.size(); i++) {
                    HrProcessActivityCardQuery card = cards.get(i);
                    HrPmProcessActivityCardEntity convert = Convert.convert(HrPmProcessActivityCardEntity.class, card);
                    convert.setPid(pid);
                    convert.setSerialUuid(serialUuid);
                    cardEntities.add(convert);

                    // 处理序列相关逻辑
                    HrProcessActivityCardQuery nextCard = i == cards.size() - 1 ? null : cards.get(i + 1);
                    boolean nextCardIsDiffSerial = nextCard != null && card.getSerialSort().intValue() != nextCard.getSerialSort().intValue();
                    // 下一个节点不是同一个序列的节点
                    if (nextCardIsDiffSerial) {
                        serialUuid = Opt.ofBlankAble(nextCard.getSerialUuid()).orElse(IdUtil.fastSimpleUUID());
                    }
                }

                processActivityCardManager.saveBatch(cardEntities);
            }


        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean copyTemplate(Long templateId, Long memberTemplateId) {
        // 查询考核模版对应的考核流程
        List<HrPmProcessTemplateEntity> processTemplateEntities = processTemplateManager.list(
                Wrappers.lambdaQuery(HrPmProcessTemplateEntity.class)
                        .eq(HrPmProcessTemplateEntity::getTemplateId, templateId)
        );
        if (CollUtil.isEmpty(processTemplateEntities)) {
            return false;
        }

        // 拷贝之前删除已存在数据
        List<HrPmProcessActivityEntity> existActivities = processActivityManager.list(
                Wrappers.lambdaQuery(HrPmProcessActivityEntity.class)
                        .eq(HrPmProcessActivityEntity::getMemberTemplateId, memberTemplateId)
        );
        if (CollUtil.isNotEmpty(existActivities)) {
            List<Long> existActivityIds = existActivities.stream().map(BaseEntity::getId).collect(Collectors.toList());
            // 删除主表原始数据
            processActivityManager.removeByIds(existActivityIds);
            // 删除卡片
            processActivityCardManager.remove(
                    Wrappers.lambdaQuery(HrPmProcessActivityCardEntity.class)
                            .in(HrPmProcessActivityCardEntity::getPid, existActivityIds)
            );
        }

        LocalDateTime now = LocalDateTime.now();
        // 保存到活动
        for (HrPmProcessTemplateEntity processTemplateEntity : processTemplateEntities) {
            // 复制模版
            HrPmProcessActivityEntity processActivityEntity = Convert.convert(HrPmProcessActivityEntity.class, processTemplateEntity);
            processActivityEntity.setMemberTemplateId(memberTemplateId);
            processActivityEntity.setId(null);
            processActivityEntity.setCreateTime(now);
            processActivityManager.save(processActivityEntity);
            // 查询模版考核流程对应的卡片
            List<HrPmProcessTemplateCardEntity> processTemplateCardEntities = processTemplateCardManager.list(
                    Wrappers.lambdaQuery(HrPmProcessTemplateCardEntity.class)
                            .eq(HrPmProcessTemplateCardEntity::getPid, processTemplateEntity.getId())
            );
            List<HrPmProcessActivityCardEntity> cardEntities = processTemplateCardEntities.stream().map(card -> {
                HrPmProcessActivityCardEntity convert = Convert.convert(HrPmProcessActivityCardEntity.class, card);
                convert.setPid(processActivityEntity.getId());
                convert.setId(null);
                convert.setCreateTime(now);
                return convert;
            }).collect(Collectors.toList());
            // 插入活动卡片
            processActivityCardManager.saveBatch(cardEntities);
        }

        return true;
    }

    @Resource
    private HrPmMemberTemplateManager memberTemplateManager;
    @Resource
    private CommonMemberService commonMemberService;

    @Override
    public List<ApprovalChainNode> getApprovalChainNodes(Long memberTemplateId, HrProcessFlowStageEnum flowStage) {
        // 获取当前阶段的活动
        HrPmProcessActivityEntity activity = processActivityManager.getOne(
                Wrappers.lambdaQuery(HrPmProcessActivityEntity.class)
                        .eq(HrPmProcessActivityEntity::getMemberTemplateId, memberTemplateId)
                        .eq(HrPmProcessActivityEntity::getFlowStage, flowStage.getType())
        );
        if (activity == null || StrUtil.isBlank(activity.getFlowStage())) {
            return Collections.emptyList();
        }

        // 获取当前阶段的卡片
        List<HrPmProcessActivityCardEntity> cards = processActivityCardManager.list(
                        Wrappers.lambdaQuery(HrPmProcessActivityCardEntity.class)
                                .eq(HrPmProcessActivityCardEntity::getPid, activity.getId())
                                .eq(HrPmProcessActivityCardEntity::getIsActive, CommonConstant.YESNO_YES)
                                .orderByAsc(HrPmProcessActivityCardEntity::getSerialSort,
                                        HrPmProcessActivityCardEntity::getParallelSort)
                ).stream()
                // 过滤无效卡片
                .filter(c -> StrUtil.isNotBlank(c.getAssignType()))
                .collect(Collectors.toList());

        if (CollUtil.isEmpty(cards)) {
            return Collections.emptyList();
        }

        List<ApprovalChainNode> approvalChainNodes = new ArrayList<>();
        // 按SerialUuid分组
        Map<String, List<HrPmProcessActivityCardEntity>> serialGroups = cards.stream()
                .collect(Collectors.groupingBy(HrPmProcessActivityCardEntity::getSerialUuid,
                        LinkedHashMap::new,
                        Collectors.toList()));

        // 处理每个SerialUuid序列组
        serialGroups.forEach((serialUuid, groupCards) -> {
            ApprovalChainNode node = new ApprovalChainNode();
            node.setApprovalName(groupCards.get(0).getCardName());
            node.setBusinessId(serialUuid);

            // 移除了去重逻辑，直接收集原始数据
            List<String> assignments = groupCards.stream()
                    .flatMap(card -> processAssignment(card, memberTemplateId).stream())
                    .collect(Collectors.toList());

            node.setAssignList(assignments);

            if (CollUtil.isNotEmpty(node.getAssignList())) {
                approvalChainNodes.add(node);
            }
        });

        return approvalChainNodes;
    }

    /**
     * 处理卡片分配逻辑
     *
     * @param card
     * @param memberTemplateId
     * @return java.util.List<java.lang.String>
     * @author zhonglj
     * @date 2025/3/10 13:06
     **/
    private List<String> processAssignment(HrPmProcessActivityCardEntity card, Long memberTemplateId) {
        List<String> assignments = new ArrayList<>(2);
        String assignType = card.getAssignType();
        String assignValue = card.getAssignValue();

        // 提前获取公共的 memberTemplate
        HrPmMemberTemplateEntity memberTemplate = memberTemplateManager.getById(memberTemplateId);
        Assert.notNull(memberTemplate, () -> new ApiException("人员考核模板不存在"));
        Assert.notNull(memberTemplate.getMemberId(), () -> new ApiException("活动考核人为空"));
        try {
            switch (ProcessCardAssignTypeEnum.getByType(assignType)) {
                case ASSIGN_SELF:
                    assignments.add(memberTemplate.getMemberId().toString());
                    break;

                case DIRECT_LEADER:
                    MemberVO memberInfo = commonMemberService.getMemberInfo(memberTemplate.getMemberId());
                    if (memberInfo == null || memberInfo.getMemberLeaderId() == null) {
                        Asserts.fail("获取上级领导为空!");
                    }
                    assignments.add(memberInfo.getMemberLeaderId().toString());
                    break;

                case ASSIGN_PERSON:
                    assignments.addAll(StrUtil.splitTrim(assignValue, ","));
                    break;

                case DEPARTMENT_MANAGER:
                    // 预留部门经理处理逻辑
                    break;

                default:
                    log.warn(StrUtil.format("未知的分配类型: {}", assignType));
            }
        } catch (Exception e) {
            log.error(StrUtil.format("处理卡片分配失败: cardId={}", card.getId()), e);
        }
        return assignments;
    }

    @Resource
    private WorkFlowService workFlowService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetWorkFlowChain(Long memberTemplateId, HrProcessFlowStageEnum stageEnum) {
        if (stageEnum == null || stageEnum.getStatusColumn() == null || stageEnum.getBusinessColumn() == null) {
            return;
        }

        // 判断人员活动表是否在审核中
        HrPmMemberTemplateEntity memberTemplateEntity = memberTemplateManager.getById(memberTemplateId);
        if (memberTemplateEntity == null) {
            return;
        }

        // 判断是否需要进行审批链重置
        Object statusVal = ReflectUtil.getFieldValue(memberTemplateEntity, StrUtil.toCamelCase(stageEnum.getStatusColumn()));
        Object businessCodeVal = ReflectUtil.getFieldValue(memberTemplateEntity, StrUtil.toCamelCase(stageEnum.getBusinessColumn()));
        if (statusVal == null || businessCodeVal == null
                || !ObjectUtil.equals(statusVal, ApproveStatus.APPROVING.getValue())) {
            return;
        }

        ArrayList<ApprovalChainNode> approvalChainNodes = CollUtil.newArrayList(getApprovalChainNodes(memberTemplateId, stageEnum));
        workFlowService.resetDynamicApprovalChain(businessCodeVal.toString(), stageEnum.getChainKey(), approvalChainNodes);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String startProcess(Long memberTemplateId, HrProcessFlowStageEnum stageEnum, ExtraBusinessDataQuery extraBusinessData) {
        if (stageEnum == null || stageEnum.getStatusColumn() == null || stageEnum.getBusinessColumn() == null) {
            Asserts.fail("人员考核活动流程阶段枚举未设置正确!");
        }

        HrPmMemberTemplateEntity memberTemplateEntity = memberTemplateManager.getById(memberTemplateId);
        if (memberTemplateEntity == null) {
            Asserts.fail("人员考核活动不存在!");
        }

        Object businessCodeVal = ReflectUtil.getFieldValue(memberTemplateEntity, StrUtil.toCamelCase(stageEnum.getBusinessColumn()));
        if (businessCodeVal == null) {
            Asserts.fail("人员考核活动业务唯一编码为空!");
        }

        ArrayList<ApprovalChainNode> approvalChainNodes = CollUtil.newArrayList(getApprovalChainNodes(memberTemplateId, stageEnum));
        if (CollUtil.isEmpty(approvalChainNodes)) {
            Asserts.fail("人员考核活动流程阶段审批人获取为空!");
        }

        // 待办中心默认是详情
        if (extraBusinessData.getBusinessType() == null) {
            extraBusinessData.setBusinessType(DcOpenTypeEnum.DETAIL.getType());
        }

        DynamicApprovalChain chain = DynamicApprovalChain.build(approvalChainNodes);
        HashMap<String, Object> map = MapUtil.of(stageEnum.getChainKey(), chain);
        String processInst = workFlowService.startProcess(stageEnum.getProcessDefKey(), TableNameUtils.getTableName(HrPmMemberTemplateEntity.class), stageEnum.getBusinessColumn(), businessCodeVal.toString(), stageEnum.getStatusColumn(), extraBusinessData, map);
        return processInst;
    }

    @Override
    public ProcessActivityNodeVO getProcessActivityNode(String businessKey) {
        List<ProcessActivityNodeVO> processActivityNode = getProcessActivityNode(CollUtil.newArrayList(businessKey));
        if (CollUtil.isNotEmpty(processActivityNode)) {
            return processActivityNode.get(0);
        }
        return null;
    }


    @Resource
    private IActProcessMappingService processMappingService;
    @Resource
    private RuntimeService runtimeService;

    @Override
    public List<ProcessActivityNodeVO> getProcessActivityNode(List<String> businessKeyList) {
        if (CollUtil.isEmpty(businessKeyList)) {
            return null;
        }
        List<ActProcessMappingEntity> mappingEntities = processMappingService.list(
                Wrappers.lambdaQuery(ActProcessMappingEntity.class)
                        .in(ActProcessMappingEntity::getBusinessKey, businessKeyList)
                        .orderByDesc(BaseEntity::getId)
        );

        if (CollUtil.isEmpty(mappingEntities)) {
            return null;
        }

        List<ProcessActivityNodeVO> nodes = new ArrayList<>();
        for (ActProcessMappingEntity mapping : mappingEntities) {
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(mapping.getProcessInstantId())
                    .singleResult();
            if (processInstance == null) {
                // 流程已经结束
                continue;
            }

            // 根据工作流实例获取档期正在执行的节点
            DynamicApprovalChain approvalChain = runtimeService.getVariable(mapping.getProcessInstantId(), HrPmCodeConstant.HR_PM_PROCESS_STAGE_CHAIN_KEY, DynamicApprovalChain.class);
            if (approvalChain == null) {
                continue;
            }

            ApprovalChainNode currentNode = approvalChain.getCurrentNode();
            List<HrPmProcessActivityCardEntity> activityCards = processActivityCardManager.list(
                    Wrappers.lambdaQuery(HrPmProcessActivityCardEntity.class)
                            .eq(HrPmProcessActivityCardEntity::getSerialUuid, currentNode.getBusinessId())
                            .orderByAsc(HrPmProcessActivityCardEntity::getParallelSort)
            );

            if (CollUtil.isEmpty(activityCards)) {
                continue;
            }

            HrPmProcessActivityCardEntity cardEntity = activityCards.get(0);
            ProcessActivityNodeVO nodeVO = new ProcessActivityNodeVO();
            nodeVO.setNodeName(cardEntity.getCardName());
            nodeVO.setNodeType(cardEntity.getCardType());
            nodeVO.setAssignList(currentNode.getAssignList());
            nodeVO.setBusinessKey(mapping.getBusinessKey());
            nodes.add(nodeVO);
        }

        return nodes;
    }
}
